package com.color.admin.system.servie.impl;

import com.color.admin.common.core.constant.Constant;
import com.color.admin.common.core.exception.BaseException;
import com.color.admin.common.core.page.PageRequest;
import com.color.admin.common.core.page.PageResponse;
import com.color.admin.common.core.utils.tools.QueryHelp;
import com.color.admin.system.entity.SysMenu;
import com.color.admin.system.entity.SysRole;
import com.color.admin.system.entity.SysUser;
import com.color.admin.system.entity.query.RoleQueryCriteria;
import com.color.admin.system.entity.vo.role.RoleSelectVo;
import com.color.admin.system.entity.vo.role.RoleVo;
import com.color.admin.system.repository.RoleRepository;
import com.color.admin.system.servie.RoleService;
import com.color.admin.system.servie.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author HaiQiu
 * @date 2021/12/22
 */
@Service
public class RoleServiceImpl implements RoleService {

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private UserService userService;


    @Override
    public void save(SysRole sysRole) {
        checkRoleNameIsExits(sysRole.getRoleName(), null);
        sysRole.setCreateTime(new Date());
        sysRole.setUpdateTime(new Date());
        SysRole role = roleRepository.save(sysRole);
        if (ObjectUtils.isEmpty(role)) {
            throw new BaseException(Constant.INSERT_FAIL);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Set<String> ids) {
        List<SysUser> sysUsers = userService.findUserByRoleIds(ids);
        if (!CollectionUtils.isEmpty(sysUsers)) {
            List<String> usersByName = sysUsers.stream().map(SysUser::getUsername).collect(Collectors.toList());
            throw new BaseException(String.format(Constant.OCCUPY, usersByName, "角色"));
        }
        if (roleRepository.deleteAllByIdIn(ids) == 0) {
            throw new BaseException(Constant.DELETE_FAIL);
        }
    }

    @Override
    public List<RoleSelectVo> roleAll(String roleName) {
        if (!com.color.admin.common.core.utils.web.StringUtils.isBlank(roleName)) {
            return getSelectRoles(roleRepository.findAllByRoleNameLike(roleName));
        }
        return getSelectRoles(roleRepository.findAll());
    }


    /**
     * 转换实体数据为下拉数据
     *
     * @param sysRoles 数据列表
     * @return 转换之后的数据
     */
    protected List<RoleSelectVo> getSelectRoles(List<SysRole> sysRoles) {
        List<RoleSelectVo> roleSelectVos = sysRoles.stream().map(new Function<SysRole, RoleSelectVo>() {
            @Override
            public RoleSelectVo apply(SysRole sysRole) {
                RoleSelectVo vo = new RoleSelectVo();
                BeanUtils.copyProperties(sysRole, vo);
                return vo;
            }
        }).collect(Collectors.toList());
        return roleSelectVos;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public SysRole get(String roleId) {
        SysRole role = roleRepository.findById(roleId).orElseGet(SysRole::new);
        return role.getId() == null ? null : role;
    }

    @Override
    public PageResponse<RoleVo> list(PageRequest<RoleQueryCriteria> request) {
        RoleQueryCriteria criteria = request.getParams();

        List<Sort.Order> orders = new ArrayList<>();
        orders.add(new Sort.Order(Sort.Direction.ASC, "sort"));
        orders.add(new Sort.Order(Sort.Direction.DESC, "updateTime"));

        Pageable pageable = org.springframework.data.domain.PageRequest.of(request.getNum(),
                request.getPageSize(), Sort.by(orders));

        Page<SysRole> page = roleRepository.findAll((root, criteriaQuery, criteriaBuilder) ->
                QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);

        Page<RoleVo> roleVos = page.map(sysRole -> {
            RoleVo roleVo = new RoleVo();
            BeanUtils.copyProperties(sysRole, roleVo);
            return roleVo;
        });

        PageResponse<RoleVo> response = new PageResponse<>();

        response.setPageSize(request.getPageSize());
        response.setTotalElements(roleVos.getTotalElements());
        response.setPageIndex(request.getPageIndex());
        response.setData(roleVos.getContent());
        return response;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(SysRole sysRole) {
        if (!StringUtils.hasText(sysRole.getId())) {
            throw new BaseException(Constant.ID_EXITS);
        }
        checkRoleNameIsExits(sysRole.getRoleName(), sysRole.getId());
        SysRole role = get(sysRole.getId());
        role.setUpdateTime(new Date());
        role.setRoleName(sysRole.getRoleName());
        role.setActive(sysRole.getActive());
        role.setIcon(sysRole.getIcon());
        role.setDescription(sysRole.getDescription());
        role.setSort(sysRole.getSort());
        if (!CollectionUtils.isEmpty(sysRole.getMenus())) {
            role.setMenus(sysRole.getMenus());
        }
        roleRepository.save(role);
    }

    @Override
    public List<SysMenu> findMenusByRoleIds(Set<String> roleIds) {
        List<SysRole> roles = roleRepository.findAllByIdIn(roleIds);
        if (!CollectionUtils.isEmpty(roles)) {
            Set<SysMenu> sysMenus = new HashSet<>();
            roles.forEach(sysRole -> {
                if (!CollectionUtils.isEmpty(sysRole.getMenus())) {
                    sysMenus.addAll(sysRole.getMenus());
                }
            });
            List<SysMenu> menus = new ArrayList<>(sysMenus);
            return menus;
        }
        return null;
    }

    private void checkRoleNameIsExits(String roleName, String roleId) {
        SysRole roleByDb = roleRepository.findByRoleName(roleName.trim());
        if (!ObjectUtils.isEmpty(roleByDb) && !roleId.equals(roleByDb.getId())) {
            throw new BaseException("该角色名已存在");
        }
    }
}
